from linear_algebra import normalize, norm, scalar_prod, lin_combine
from copy import copy, deepcopy
import population
import math


def assignValue(entry, population, value, maxSize, factor = 1):
            if hasattr(entry, "tries"):
                population.valuate(entry, value)
            else:
                population.add(entry, new_value)

                population.size_aggreg += len(population)

                if population.size_aggreg > factor * maxSize:
                    population.size_aggreg -= factor * maxSize
                    population.kill(pop[-1])


def adapt(examples, population, hof, hos, seed_size, combine, seed_combine):
    """Adapts a specimen selected from population."""
    specimen = population.select()

    old_value = examples.evaluate(specimen)
    # set old_value as evaluation of specimen

    candidate = hof.select()
    seed = []
    for i in xrange(population.seed_size):
        seed.append(hos.select())

    dither = seed_combine(seed)
    length = (specimen.adaption_length + norm(candidate)) * 0.25
    adaption = scalar_prod(combine(normalize(candidate), dither), length)

    # the new error value (so smaller is better)
    new_value = examples.evaluate(adaption.testOn(specimen))
    # quotient value, to measure adaption-performance
    quot_value = new_value/old_value


    improved = new_value < old_value


    assignValue(candidate, hof, quot_value)
    for s in seed:
        assignValue(s, hos, quot_value)

    if improved:
        adaption.applyTo(specimen)

        specimen.adaption_length += norm(adaption)
        specimen.adaption_length *= 0.5

        assignValue(specimen, population, new_value)
        self.hof.add(adaption, quot_value)

        return new_value

    else:
        assignValue(specimen, population, old_value)
        hos.add(adaption, 1/quot_value)
        specimen.adaption_length *= 0.5

        return old_value


def defaultCombine(v1, v2):
    return lin_combine(v1, v2)

def defaultSeedCombine(seed):
    result = deepcopy(seed[0])
    for s in seed[1:]:
        result = defaultCombine(result, s)

    result = normalize(result)
    return result

